package com.ruoyi.iot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.iot.constant.LiveViewTypeEnum;
import com.ruoyi.iot.constant.MateConstant;
import com.ruoyi.iot.domain.*;
import com.ruoyi.iot.service.*;
import com.ruoyi.iot.util.EzopenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class FacDeviceMonitorDataServiceImpl implements IFacDeviceMonitorDataService {

    @Autowired
    IFacDeviceBasicService facDeviceBasicService;

    @Autowired
    IFacDevicesTypeService facDevicesTypeService;

    @Autowired
    IFacDevicesMonitorService facDevicesMonitorService;

    @Autowired
    IFacDevicesRundataService facDevicesRunDataService;

    @Autowired
    IFacDevicesMonitorParamService facDevicesMonitorParamService;

    @Autowired
    DbService dbService;
    @Override
    public Map<String, Object> getDeviceLastData(DeviceDataRequest request) {
        Long id=request.getDeviceId();
//        FacDevices device = devicesService.getById(id);
        //根据设备ID获取设备信息
        FacDeviceBasic deviceInf=facDeviceBasicService.selectFacDeviceBasicById(id);
        if(ObjectUtil.isNotEmpty(deviceInf)){
            //获取设备型号
            FacDevicesType typeEntity=new FacDevicesType();
            typeEntity.setCode(deviceInf.getTypeCode());
            List<FacDevicesType> typeList= facDevicesTypeService.selectFacDevicesTypeList(typeEntity);
            if(ObjectUtil.isNotEmpty(typeList) && typeList.size()>0) {
                FacDevicesType currType = typeList.get(0);
                //根据型号获取监测类型
                FacDevicesMonitor queryEntity = new FacDevicesMonitor();
                queryEntity.setTypeId(currType.getId());
                List<FacDevicesMonitor> monitorList = facDevicesMonitorService.selectFacDevicesMonitorList(queryEntity);
                if (ObjectUtil.isNotEmpty(monitorList) && monitorList.size() > 0) {
                    //根据设备获取对接数据
                    FacDevicesRundata runDataQuery=new  FacDevicesRundata();
                    runDataQuery.setDeviceId(deviceInf.getId());
                    List<FacDevicesRundata> runDataList=facDevicesRunDataService.selectFacDevicesRundataList(runDataQuery);
                    if(ObjectUtil.isNotEmpty(runDataList)){
                        Map<String, Object> dataKv=new HashMap<>(5);
                        Map<String, Object> kv=new HashMap<>(5);
                        for (FacDevicesMonitor monitorVo:monitorList){
                            Map<String, Object> data=getLastData(deviceInf, monitorVo, runDataList.get(0), null);
                            kv.put(monitorVo.getTablePrefix(),data.get("data"));
                        }
                        dataKv.put("data",kv);
                        return dataKv;
                    }
                }
            }
        }
        return null;
    }


    @Override
    public HashMap playVideo(DeviceDataRequest request) {
        HashMap kv=new HashMap(3);
        //根据设备编号获取设备
        Long deviceId=request.getDeviceId();
        FacDeviceBasic deviceInf=facDeviceBasicService.selectFacDeviceBasicById(deviceId);
        if(ObjectUtil.isNotEmpty(deviceInf)){
            //根据设备编号获取对接信息
            FacDevicesRundata queryEntity=new FacDevicesRundata();
            queryEntity.setDeviceId(deviceId);
            List<FacDevicesRundata> runDataList=facDevicesRunDataService.selectFacDevicesRundataList(queryEntity);
            if(ObjectUtil.isNotEmpty(runDataList) && runDataList.size()>0){
                FacDevicesRundata currRunData=runDataList.get(0);
                LiveViewTypeEnum urlType = LiveViewTypeEnum.find(currRunData.getDataMode());
                switch (urlType){
                    case WEBRTC:
//                        rtspToWebrtc(kv, id, rundata);
                        break;
                    case RTMP:
                        kv.put("streamUrl",currRunData.getuUrl());
                        kv.put("viewType",LiveViewTypeEnum.RTMP);
                        break;
                    case YS7:
                        String token= EzopenUtil.getToken(currRunData.getuName(),currRunData.getuPassword());
//                        String viewCode= (String) prop.get("view_code");
//                        String viewChannel= (String) prop.get("view_channel");
//                        kv.put("viewCode",ObjectUtil.isNotEmpty(viewCode)?viewCode:"");
//                        kv.put("viewChannel",ObjectUtil.isNotEmpty(viewChannel)?viewChannel:"");
                        kv.put("appkey",currRunData.getuName());
                        kv.put("streamUrl",currRunData.getuUrl());
                        kv.put("token", token);
                        kv.put("viewType",LiveViewTypeEnum.YS7);
                        break;
                    case H5:
                        kv.put("streamUrl",currRunData.getuUrl());
                        kv.put("viewType",LiveViewTypeEnum.H5);
                        break;
                }
                return kv;
            }
        }
        return null;
    }

    @Override
    public Map<String, Object> getDevicePageData(DeviceDataRequest request) {
        Long id=request.getDeviceId();
        FacDeviceBasic deviceInf = facDeviceBasicService.selectFacDeviceBasicById(id);
        if(ObjectUtil.isNotEmpty(deviceInf)){
            //根据型号编码获取设备型号
            FacDevicesType typeEntity=new FacDevicesType();
            typeEntity.setCode(deviceInf.getTypeCode());
            List<FacDevicesType> typeList= facDevicesTypeService.selectFacDevicesTypeList(typeEntity);
            if(ObjectUtil.isNotEmpty(typeList) && typeList.size()>0) {
                //根据设备型号获取监测类型
                FacDevicesType currType = typeList.get(0);
                //根据型号获取监测类型
                FacDevicesMonitor queryEntity = new FacDevicesMonitor();
                queryEntity.setTypeId(currType.getId());
                List<FacDevicesMonitor> monitorList = facDevicesMonitorService.selectFacDevicesMonitorList(queryEntity);
                //根据设备获取运行数据
                if (ObjectUtil.isNotEmpty(monitorList) && monitorList.size() > 0) {
                    //根据设备获取对接数据
                    FacDevicesRundata runDataQuery = new FacDevicesRundata();
                    runDataQuery.setDeviceId(deviceInf.getId());
                    List<FacDevicesRundata> runDataList = facDevicesRunDataService.selectFacDevicesRundataList(runDataQuery);
                    if (ObjectUtil.isNotEmpty(runDataList)) {
                        Map<String, Object> dataKv=new HashMap<>(5);
                        Map<String, Object> kv=new HashMap<>(5);
                        for (FacDevicesMonitor monitorVo:monitorList){
                            Map<String, Object> data=getPageData(request,deviceInf, monitorVo, runDataList.get(0),null);
                            kv.put(monitorVo.getTablePrefix(),data.get("data"));
                        }
                        dataKv.put("data",kv);
                        return dataKv;
                    }
                }
            }

        }
        return null;
    }

    /***
     * 递归获取最新数据
     * @param device
     * @param monitorVo
     * @param rundata
     * @param dataId
     * @return
     */
    private Map<String, Object> getLastData(FacDeviceBasic device, FacDevicesMonitor monitorVo,FacDevicesRundata rundata, String dataId) {
        HashMap<String,Object> data=new HashMap<>(12);
        Long id=device.getId();
        String tablename= monitorVo.getTableName();
        String isSplit= rundata.getIsSplit();
        String deviceCode="";
        if (MateConstant.YES.equalsIgnoreCase(isSplit)) {
            deviceCode = device.getDeviceSn();
            tablename+="_"+deviceCode.toLowerCase();
        }
        //获取类型对应的监控字段集合
        FacDevicesMonitorParam queryEntity=new  FacDevicesMonitorParam();
        queryEntity.setMonitorId(monitorVo.getId());
        List<FacDevicesMonitorParam> paramList=facDevicesMonitorParamService.selectFacDevicesMonitorParamList(queryEntity);
        String ficFiels="";
        for (FacDevicesMonitorParam param:paramList) {
            if(MateConstant.YES.equals(param.getIsFix())){
                ficFiels=param.getField();
                break;
            }
        }
        //字段表数据获取
        if (MateConstant.DATA_FIELD.equals(monitorVo.getDataClass())){
//            getFieldLastData(device, monitorVo, rundata,dataId, data, id, tablename, ficFiels);

        }
        else if(MateConstant.DATA_TABLE.equals(monitorVo.getDataClass())) {
            getTableLastData(device, monitorVo,paramList, rundata, dataId, data, id, tablename);
        }
        return  data;
    }

    /**
     * 字段表最新数据获取
     */
    private void getFieldLastData(FacDeviceBasic device, FacDevicesMonitor monitorVo, FacDevicesRundata rundata,String dataId, HashMap<String, Object> data, Long id, String tablename, String ficFiels) {

    }
    /**
     * table表最新数据获取
     */
    private void getTableLastData(FacDeviceBasic device, FacDevicesMonitor monitorVo,List<FacDevicesMonitorParam> paramList, FacDevicesRundata rundata, String dataId, HashMap<String, Object> data, Long id, String tablename) {
        String whsql="";
        if (ObjectUtil.isNotEmpty(dataId)) {
            whsql=" and data_id="+ dataId;

        }
        String sql="SELECT * FROM " + tablename +" where device_id="+ id +" and monitoring_time=(select max(monitoring_time) FROM "+ tablename +" where device_id="+ id +whsql +")";
        List<Map<String,Object>> ll=dbService.getList(sql);
        List<Map> dataList= BeanUtil.copyToList(ll,Map.class);
        if(ObjectUtil.isNotEmpty(dataList)){
            //根据监测类型获取子的监测类型
            FacDevicesMonitor queryChild=new FacDevicesMonitor();
            queryChild.setPid(monitorVo.getId());
            List<FacDevicesMonitor> childList=facDevicesMonitorService.selectFacDevicesMonitorList(queryChild);
            for(Map mm:dataList){
                if (ObjectUtil.isNotEmpty(childList)) {
                    for (FacDevicesMonitor vo : childList) {
                        Map<String,Object> dd=getLastData(device,vo, rundata, (String) mm.get("id"));
                        if(ObjectUtil.isNotEmpty(dd.get("data"))) {
                            mm.put(vo.getTablePrefix(), dd.get("data"));
                        }else{
                            mm.put(vo.getTablePrefix(), ListUtil.empty());
                        }
                    }
                }
            }
            setFieldByType(monitorVo,paramList, dataList);
            if(dataList.size()>1 || ObjectUtil.isNotEmpty(dataId)) {
                data.put("data",dataList);
            }else{
                data.put("data",dataList.get(0));
            }
        }else{
            if(ObjectUtil.isNotEmpty(dataId)) {
                data.put("data",null);
            }else {
                data.put("data", new HashMap<>(0));
            }
        }
    }
    /**
     * 设置字段类型值
     * @param monitorVo
     * @param dataList
     */
    private void setFieldByType(FacDevicesMonitor monitorVo,List<FacDevicesMonitorParam> paramList, List<Map> dataList) {
        for(Map<String,Object> dm: dataList){
            HashMap kv=new HashMap(5);
            for(String key:dm.keySet()) {
                for (FacDevicesMonitorParam p :paramList) {
                    if(key.equals(p.getField())){
                        /**图片数据**/
//                        if(FieldTypeEnums.IMAGES.getCode().equals(p.getFieldType())){
//                            if(ObjectUtil.isNotEmpty(dm.get(key))){
//                                dm.put(key,ListUtil.toList(dm.get(key)));
//                            }
//                        }
                        /**枚举数据**/
//                        if(ObjectUtil.isNotEmpty(p.getFieldValue())){
//                            Object obj=dm.get(key);
//                            String tt= ObjectUtil.isNotEmpty(obj)?obj.toString():"-";
//                            DictObject dict=systemService.getDictValue(p.getFieldValue(),tt).getData();
//                            dm.put(key,dict.getText());
//                        }
                        /**标准字段**/
//                        if(ObjectUtil.isNotEmpty(p.getStandardField())){
//                            kv.put(p.getStandardField(),dm.get(key));
//                        }
                        /**分层**/
//                        if(MateConstant.YES.equals(p.getIsFix())){
//                            kv.put("scope", dm.get(key));
//                        }
                        break;
                    }
                }
            }
//            dm.putAll(kv);
        }
    }

    /** 获取监测数据分页列表 辅助函数*/
    private Map<String, Object> getPageData(DeviceDataRequest request,FacDeviceBasic device, FacDevicesMonitor monitorVo, FacDevicesRundata rundata, Long dataId) {
        HashMap<String,Object> data=new HashMap<>(12);
        Long id=device.getId();
        String tablename= monitorVo.getTableName();
        String isSplit= rundata.getIsSplit();
        String deviceCode="";
        if (MateConstant.YES.equalsIgnoreCase(isSplit)) {
            deviceCode = device.getDeviceSn();
            tablename+="_"+deviceCode.toLowerCase();
        }
        //获取字段集合
        //获取类型对应的监控字段集合
        FacDevicesMonitorParam queryEntity=new  FacDevicesMonitorParam();
        queryEntity.setMonitorId(monitorVo.getId());
        List<FacDevicesMonitorParam> paramList=facDevicesMonitorParamService.selectFacDevicesMonitorParamList(queryEntity);
        monitorVo.setFieldList(paramList);
        String ficFiels="";
        for (FacDevicesMonitorParam param:paramList) {
            if(MateConstant.YES.equals(param.getIsFix())){
                ficFiels=param.getField();
                break;
            }
        }
        List<String> codeList = request.getCodeList();
        String starttime = "";
        String endtime = "";
        if(ObjectUtil.isEmpty(request.getStartTime())){
            starttime=" timestamp '"+ LocalDateTimeUtil.format(DateUtil.offsetMonth(new Date(),-6).toLocalDateTime(), DatePattern.NORM_DATETIME_PATTERN)+"' ";
        }else{
            starttime=" timestamp '"+LocalDateTimeUtil.format(request.getStartTime(),DatePattern.NORM_DATETIME_PATTERN)+"' ";
        }
        if(ObjectUtil.isEmpty(request.getEndTime())){
            endtime=" timestamp '"+LocalDateTimeUtil.format(LocalDateTime.now(),DatePattern.NORM_DATETIME_PATTERN)+"' ";
        }else{
            endtime=" timestamp '"+LocalDateTimeUtil.format(request.getEndTime(),DatePattern.NORM_DATETIME_PATTERN)+"' ";
        }
        if (MateConstant.DATA_FIELD.equals(monitorVo.getDataClass())){
//            getFieldPageData(request, device, monitorVo, rundata, dataId, data, id, tablename, ficFiels, codeList, starttime, endtime);

        }
        if(MateConstant.DATA_TABLE.equals(monitorVo.getDataClass())) {
            getTablePageData(request, device, monitorVo, rundata, dataId, data, id, tablename, ficFiels, codeList, starttime, endtime);
        }
        return data;
    }

    private HashMap<String, Object> getTablePageData(DeviceDataRequest request, FacDeviceBasic device, FacDevicesMonitor monitorVo, FacDevicesRundata rundata, Long dataId, HashMap<String, Object> data, Long id, String tablename, String ficFiels, List<String> codeList, String starttime, String endtime) {
        String sql;
        String countsql;
        String codesql;
        String whsql="";
        if (ObjectUtil.isNotEmpty(dataId)) {
            whsql=" and data_id="+ dataId;
        }
        String insql="";
        List<String> cclist=new ArrayList<>();
        if(ObjectUtil.isNotEmpty(codeList)) {
            for (String code : codeList) {
                for (FacDevicesMonitorParam param : monitorVo.getFieldList()) {
                    if (code.equals(param.getField())) {
                        cclist.add(param.getField());
                    }
                }
            }
        }else{
            for (FacDevicesMonitorParam param : monitorVo.getFieldList()) {
                cclist.add(param.getField());
            }
        }
        if(ObjectUtil.isNotEmpty(cclist)){
            insql="id,device_id,monitoring_time,"+(ObjectUtil.isNotEmpty(ficFiels)? (ficFiels+",") :"")+"\""+ StrUtil.join("\",\"", cclist)+"\"";
        }else {
            insql="*";
        }
        codesql="SELECT DISTINCT "+(ObjectUtil.isNotEmpty(ficFiels)? ficFiels :"device_id")+" FROM " + tablename +
                " where device_id="+ id +" and monitoring_time>"+ starttime +"and monitoring_time<"+ endtime;
        List<Map<String,Object>> namelist=dbService.getList(codesql);
        if(ObjectUtil.isEmpty(namelist)){
            data.put("data",null);
            return data;
        }
        countsql="SELECT count(DISTINCT monitoring_time) FROM " + tablename +
                " where device_id="+ id +" and monitoring_time>"+ starttime +"and monitoring_time<"+ endtime;
        int count= dbService.count(countsql);
        int totals=count;
        int pages=totals/ request.getPagesize();
        int size= request.getPagesize();
        int offfset=(request.getPageindex()-1)*size;
        sql="SELECT "+insql+"  FROM " + tablename +
                " where (device_id,monitoring_time) in (select DISTINCT device_id ,monitoring_time  FROM " + tablename +
                " where device_id="+ id +" and monitoring_time>"+ starttime +" and monitoring_time<"+ endtime
                +whsql+"  order by monitoring_time desc  limit "+size+" offset "+offfset+") "+whsql+" order by monitoring_time desc";
        List<Map<String,Object>> ll=dbService.getList(sql);
        List<Map> dataList= BeanUtil.copyToList(ll,Map.class);
        if(ObjectUtil.isNotEmpty(dataList)){
            getTablePageData(request, device, monitorVo, rundata, data, ficFiels, totals, pages, dataList);
        }else{
            data.put("data",null);
        }
        return data;
    }
    /**
     * 获取table类型运行数据分页
     * @param request
     * @param device
     * @param monitorVo
     * @param rundata
     * @param data
     * @param ficFiels
     * @param totals
     * @param pages
     * @param dataList
     */
    private void getTablePageData(DeviceDataRequest request, FacDeviceBasic device, FacDevicesMonitor monitorVo, FacDevicesRundata rundata, HashMap<String, Object> data, String ficFiels, int totals, int pages, List<Map> dataList) {
        String sql;
        String tablename;
        List<String> fieldList=ListUtil.toList(dataList.get(0).keySet());
        fieldList.remove("id");
        fieldList.remove("device_id");
        fieldList.remove("monitoring_time");
        fieldList.remove(ficFiels);
        List<String> scopelist=new ArrayList<>();
        List<LocalDateTime> timeList=new ArrayList<>();
        for(Map<String,Object> map: dataList){
            if(!scopelist.contains(map.get(ficFiels))){
                scopelist.add((String) map.get(ficFiels));
            }
            if(!timeList.contains(map.get("monitoring_time"))){
                timeList.add( ((Timestamp)map.get("monitoring_time")).toLocalDateTime());
            }
        }
        //倒序
        ListUtil.sort(timeList, new Comparator<LocalDateTime>() {
            @Override
            public int compare(LocalDateTime o1, LocalDateTime o2) {
                return o2.compareTo(o1);
            }
        });
        if(scopelist.size()>1) {
            HashMap codemap=new HashMap(10);
            for(String code:fieldList) {
                List<Map> rlist = new ArrayList<>();
                for(LocalDateTime time:timeList){
                    HashMap mm=new HashMap(10);
                    mm.put("monitoring_time",time);
                    for (Map<String, Object> map : dataList) {
                        if(ObjectUtil.equals(time,map.get("monitoring_time"))){
                            mm.put(map.get(ficFiels),map.get(code));
                            Map<String,Object> cmap=new HashMap<>(3);
                            //获取子项
                            FacDevicesMonitor queryChild=new FacDevicesMonitor();
                            queryChild.setPid(monitorVo.getId());
                            List<FacDevicesMonitor> childList=facDevicesMonitorService.selectFacDevicesMonitorList(queryChild);
                            for (FacDevicesMonitor vo : childList) {
                                tablename = vo.getTableName();
                                tablename="\""+tablename+"\"";
                                if (MateConstant.YES.equals(rundata.getIsSplit())) {
                                    tablename += "_" + device.getDeviceSn().toLowerCase();
                                }
                                sql = "SELECT *  FROM " + tablename +
                                        " where data_id="+map.get("id")+ " order by monitoring_time desc";
                                List<Map<String,Object>> ll=dbService.getList(sql);
                                List<Map> dll= BeanUtil.copyToList(ll,Map.class);
                                cmap.put(vo.getTablePrefix(),dll);
                            }
                            mm.putAll(cmap);

                        }
                    }
                    rlist.add(mm);
                }
                setFieldByType(monitorVo,monitorVo.getFieldList(), dataList);
                PageInfo page=new PageInfo();
                page.setPageIndex(request.getPageindex());
                page.setPageSize(request.getPagesize());
                page.setTotal(totals);
                page.setPages(pages);
                page.setRows(rlist);
                codemap.put(code,page);
            }
            data.put("data",codemap);
        }else{
            for(Map<String,Object> map: dataList) {
                getchildenData(device, monitorVo, rundata, map);
            }
            setFieldByType(monitorVo,monitorVo.getFieldList(), dataList);
            PageInfo page=new PageInfo();
            page.setPageIndex(request.getPageindex());
            page.setPageSize(request.getPagesize());
            page.setTotal(totals);
            page.setPages(pages);
            page.setRows(dataList);
            data.put("data",page);
        }
    }
    /**
     * 设置子数据
     * @param device
     * @param monitorVo
     * @param rundata
     * @param map
     */
    private void getchildenData(FacDeviceBasic device, FacDevicesMonitor monitorVo, FacDevicesRundata rundata, Map<String, Object> map) {
        String tablename;
        String sql;
        Map<String, Object> cmap = new HashMap<>(3);
        FacDevicesMonitor queryChild=new FacDevicesMonitor();
        queryChild.setPid(monitorVo.getId());
        List<FacDevicesMonitor> childList=facDevicesMonitorService.selectFacDevicesMonitorList(queryChild);
        for (FacDevicesMonitor vo : childList) {
            tablename = vo.getTableName();
            tablename="\""+tablename+"\"";
            if (MateConstant.YES.equals(rundata.getIsSplit())) {
                tablename += "_" + device.getDeviceSn().toLowerCase();
            }
            sql = "SELECT *  FROM " + tablename + " where data_id=" + map.get("id") + " order by monitoring_time desc";
            List<Map<String, Object>> ll = dbService.getList(sql);
            List<Map> dll = BeanUtil.copyToList(ll, Map.class, CopyOptions.create().setFieldValueEditor((fileName, fileValue) -> {
                if (fileValue instanceof Long) {
                    return Convert.convert(String.class, fileValue);
                }
                return fileValue;
            }));
            setFieldByType(monitorVo,monitorVo.getFieldList(), dll);
            cmap.put(vo.getTablePrefix(), dll);
        }
        ///map.put("childdata", cmap);
        map.putAll(cmap);
    }



}
